package org.example.memora.service.serviceImpl;

import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import com.zaxxer.hikari.util.PropertyElf;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.memora.DTO.UserDTO;
import org.example.memora.DTO.UserLoginDTO;
import org.example.memora.DTO.UserRedisDTO;
import org.example.memora.common.result.Result;
import org.example.memora.common.utils.RegexUtils;
import org.example.memora.common.utils.UserHolder;
import org.example.memora.controller.UserController;
import org.example.memora.entity.User;
import org.example.memora.mapper.UserMapper;
import org.example.memora.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import cn.hutool.core.bean.BeanUtil;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static org.example.memora.common.constant.LoginConstants.LOGIN_BY_CODE;
import static org.example.memora.common.constant.LoginConstants.LOGIN_BY_PASSWORD;
import static org.example.memora.common.constant.RedisConstants.*;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserMapper userMapper;
    private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    @Override
    public User getUserByUsername(String username){
        User user = userMapper.findByUsername(username);
        return user;

    }
    @Override
    public Result<?> sendCode(String phone){
        // 1.校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合，返回错误信息
            return Result.error("手机号格式错误！");
        }
        // 3.符合，生成验证码
        String code = RandomUtil.randomNumbers(6);

        // 4.保存验证码到 session
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);

        // 5.发送验证码
        //TODO:调用阿里云真正发送验证码
        log.info("发送短信验证码成功，验证码：{}", code);
        // 返回ok
        return Result.success();
    }
    @Override
    public Result<?> login(UserLoginDTO loginForm){
        User user=null;
        if(loginForm.getPattern()==LOGIN_BY_CODE){
            // 1.校验手机号
            String identifier = loginForm.getIdentifier();
            if (RegexUtils.isPhoneInvalid(identifier)) {
                // 2.如果不符合，返回错误信息
                return Result.error("手机号格式错误！");
            }
            // 3.从redis获取验证码并校验
            String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + identifier);
            String code = loginForm.getPasswordOrCode();
            if (cacheCode == null || !cacheCode.equals(code)) {
                // 不一致，报错
                return Result.error("验证码错误");
            }

            // 4.一致，根据手机号查询用户 select * from tb_user where phone = ?
            user = getUserByPhone(identifier);

            // 5.判断用户是否存在
            if (user == null) {
                // 6.不存在
                return Result.error("用户不存在，请先注册用户");
            }
        }else if(loginForm.getPattern()==LOGIN_BY_PASSWORD){
            String identifier=loginForm.getIdentifier();
            if (identifier==null) {
                return  Result.error(0, "用户名/电话/邮箱或密码为空");
            }

            if(RegexUtils.isPhoneValid(identifier)){
                user=getUserByPhone(identifier);
            }else if(RegexUtils.isEmailValid(identifier)){
                user=getUserByEmail(identifier);
            }else{
                user=getUserByUsername(identifier);
            }
            if (user == null) {
                return Result.error(0, "用户不存在");
            }
            if(!passwordEncoder.matches(loginForm.getPasswordOrCode(), user.getPassword())){
                return  Result.error(0, "密码错误");
            }
        }else{
            return  Result.error("无此登录模式，patter为0，代表手机验证码登录，pattern为1，代表手机/用户名/邮箱+密码登录");
        }
        // 7.保存用户信息到 redis中
        // 7.1.随机生成token，作为登录令牌
        String token = UUID.randomUUID().toString();
        log.info("登录成功，token：{}",token);
        // 7.2.将User对象转为HashMap存储

        UserRedisDTO userRedisDTO = BeanUtil.copyProperties(user, UserRedisDTO.class);
        userRedisDTO.setToken(token);
        Map<String, Object> userMap = BeanUtil.beanToMap(userRedisDTO, new HashMap<>(), CopyOptions.create()
                .setIgnoreNullValue(true)
                .setFieldValueEditor((fieldName, fieldValue) -> {
                    return fieldValue == null ? null : fieldValue.toString();
                })
        );
        // 7.3.存储
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        // 7.4.设置token有效期
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
        return Result.success(token); // 登录成功
    }

    @Override
    public List<User> getAllUsers() {
        return userMapper.findAll();
    }

    @Override
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }

    @Override
    public Result<?> createUser(UserDTO userDTO) {
        User user = new User();
        user.setUsername(userDTO.getUsername());
        user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        user.setEmail(userDTO.getEmail());
        user.setPhone(userDTO.getPhone());
        user.setAvatarUrl(userDTO.getAvatarUrl());
        user.setNickname(userDTO.getNickname());
        user.setGender(userDTO.getGender());
        user.setBirthday(userDTO.getBirthday());
        user.setSchool(userDTO.getSchool());
        user.setRegion(userDTO.getRegion());
        user.setBio(userDTO.getBio());
        if (RegexUtils.isPhoneInvalid(user.getPhone())) {
            // 2.如果不符合，返回错误信息
            return Result.error("手机号格式错误！");
        }
        if (RegexUtils.isEmailInvalid(user.getEmail())) {
            // 2.如果不符合，返回错误信息
            return Result.error("邮箱格式错误！");
        }

        if(userMapper.findByUsername(userDTO.getUsername())!=null){
            return Result.error(0,"用户名已被占用");
        }
        if(userMapper.findByPhone(userDTO.getPhone())!=null){
            return Result.error(0,"电话号已被占用");
        }
        if(userMapper.findByEmail(userDTO.getEmail())!=null){
            return Result.error(0,"邮箱已被占用");
        }
        userMapper.save(user);
        return Result.success();
    }

    @Override
    public Result<?> updateUser(Long id, UserDTO userDTO) {
        User existingUser = userMapper.findById(id);
        if (existingUser == null) {
            return Result.error(0, "用户不存在");
        }
        if (!userDTO.getPhone().isEmpty()&&RegexUtils.isPhoneInvalid(userDTO.getPhone())) {
            // 2.如果不符合，返回错误信息
            return Result.error("手机号格式错误！");
        }
        if (!userDTO.getEmail().isEmpty()&&RegexUtils.isEmailInvalid(userDTO.getEmail())) {
            // 2.如果不符合，返回错误信息
            return Result.error("邮箱格式错误！");
        }

        // 1. username、email、phone 三个字段有变更时才查重
        if (userDTO.getUsername() != null && !userDTO.getUsername().isBlank() && !userDTO.getUsername().equals(existingUser.getUsername())) {
            User other = userMapper.findByUsername(userDTO.getUsername());
            if (other != null) {
                return Result.error(0, "该用户名已被占用");
            }
            existingUser.setUsername(userDTO.getUsername());
        }

        if (userDTO.getEmail() != null && !userDTO.getEmail().isBlank() && !userDTO.getEmail().equals(existingUser.getEmail())) {
            User other = userMapper.findByEmail(userDTO.getEmail());
            if (other != null) {
                return Result.error(0, "该邮箱已被占用");
            }
            existingUser.setEmail(userDTO.getEmail());
        }

        if (userDTO.getPhone() != null && !userDTO.getPhone().isBlank() && !userDTO.getPhone().equals(existingUser.getPhone())) {
            User other = userMapper.findByPhone(userDTO.getPhone());
            if (other != null) {
                return Result.error(0, "该手机号已被占用");
            }
            existingUser.setPhone(userDTO.getPhone());
        }

        // 2. 其它字段更新（只更新有值的）
        if (userDTO.getPassword() != null && !userDTO.getPassword().isBlank()) {
            existingUser.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        }
        if (userDTO.getAvatarUrl() != null) existingUser.setAvatarUrl(userDTO.getAvatarUrl());
        if (userDTO.getNickname() != null) existingUser.setNickname(userDTO.getNickname());
        if (userDTO.getGender() != null) existingUser.setGender(userDTO.getGender());
        if (userDTO.getBirthday() != null) existingUser.setBirthday(userDTO.getBirthday());
        if (userDTO.getSchool() != null) existingUser.setSchool(userDTO.getSchool());
        if (userDTO.getRegion() != null) existingUser.setRegion(userDTO.getRegion());
        if (userDTO.getBio() != null) existingUser.setBio(userDTO.getBio());

        // 3. 执行更新
        userMapper.update(existingUser);
        return Result.success(existingUser);
    }

    @Override
    public Result<?> deleteUser(Long id) {
        //TODO：删除与其相关的所有数据库数据
        if(userMapper.findById(id)==null){
            return Result.error("删除失败，未查找到该用户");
        }
        userMapper.deleteById(id);
        return Result.success();
    }
    @Override
    public User getUserByPhone(String phone){
        User user=userMapper.findByPhone(phone);
        return user;
    }
    @Override
    public User getUserByEmail(String email){
        User user=userMapper.findByEmail(email);
        return user;
    }
    @Override
    public Result<?> logout(){
        UserRedisDTO userRedisDTO= UserHolder.getUser();
        if(userRedisDTO!=null){
            String token=userRedisDTO.getToken();
            String tokenKey = LOGIN_USER_KEY + token;
            stringRedisTemplate.delete(tokenKey);
        }
        return Result.success();
    }
}
